var fs = require('fs');
var traverse = require('@babel/traverse').default;
var generator = require('@babel/generator').default;
var parser = require('@babel/parser');
var t = require('@babel/types');


// var fs = require('fs');
// var parser = require('@babel/parser');
// var traverse = require('@babel/traverse').default;
// var t = require('@babel/types');
// var generator = require('@babel/generator').default;


var jscode = fs.readFileSync(`${__dirname}/code.js`,{encoding:'utf-8'});
var fs_w = `${__dirname}/resdecrypt.js`
var ast = parser.parse(jscode);
traverse(ast,{
    VariableDeclarator:del_var
});
traverse(ast,{
    FunctionDeclaration:del_qt_func,
    FunctionExpression:del_qt_func,
    ArrowFunctionExpression:del_qt_func
})
var code = generator(ast,{compact:false}).code;
fs.writeFile(fs_w,code,(err)=>{return err});

// xx清空赋值不为对象列表的局部变量xx qing  ==>t.isMemberExpression(node.init)||
function del_var(path){
    var node = path.node;
    var scope = path.scope;
    if(!(t.isIdentifier(node.init)||t.isLiteral(node.init)))return;
    // 局部作用域
    var binding = scope.getBinding(node.id.name);
    if(!(binding&&binding.references&&binding.constant))return; //
    // scope.getBinding 获取局部作用域中的对象
    if(t.isObjectExpression(node.init)||t.isArrayExpression(node.init)){
        binding.referencePaths.map((refer_path)=>{
            let bindpath = refer_path.parentPath; 
            let bindname = bindpath.node.name;
            if(t.isVariableDeclarator(bindpath.node)){
                if(!t.isIdentifier(bindpath.init,{name:node.id.name}))return;
                bindpath.scope.rename(bindname,node.id.name,bindpath.scope.block);
                bindpath.remove();
            };
            if(t.isAssignmentExpression(bindpath.node)){
                if(
                    t.isIdentifier(bindpath.node.left)&&
                    t.isIdentifier(bindpath.node.right,{name:node.id.name})
                ){
                    bindpath.scope.rename(bindname,node.id.name,bindpath.scope.block);
                    bindpath.remove();
                }
            }
        });
    }else{
        binding.referencePaths.map((refer_path)=>{
            refer_path.replaceWith(node.init);
        });
        path.remove();
    }
};
// 嵌套函数的定义，简单的数组操作，运算。body为ReturnStatement
// 识别清空嵌套函数，
function del_qt_func(path){
    var node = path.node;
    var body = node.body.body[0];
    const parentpath = path.parentPath;
    if(!(t.isReturnStatement(body)))return;
    if(t.isFunction(body.argument))return;
    if(t.isFunctionDeclaration(node)){
        var funcName = node.id.name;
        if(funcName=='_U__'){debugger};
        // 查看引用
        var binding = parentpath.scope.getBinding(node.id.name);
    }else if(t.isFunctionExpression(node)||t.isArrowFunctionExpression(node)){
        if(!t.isVariableDeclarator(parentpath.node))return;
        let referName = parentpath.node.id.name;
        var binding = parentpath.scope.getBinding(referName);
        // 查看引用
    };
    // 统一处理引用
    if(!(binding&&binding.constant&&binding.references))return;
    binding.referencePaths.map((referpath)=>{
        // 此处的referpath只指引用对象==>是个identifier
        if(!(referpath.key=='callee'))return;
        if(!(t.isIdentifier(referpath.container.callee)))return;
        var arguments__ = referpath.container.arguments;
        var arguments_ = []
        var index__=true;
        arguments__.forEach((ele,index)=>{
            if(!t.isIdentifier(ele)){
                index__=false;
            }
            var res = generator(ele).code;
            if(res.indexOf('=')!=-1){
                res = '(' + res + ')';
                console.log(res)
            }
            arguments_[index] = res;
        });
        if(!index__)return;
        let ast = parser.parse(path.toString());
        // traverse的方式是迭代循环所以要过滤上下path.node.type要一致
        traverse(ast,{
            Function:function(_path){
                var node = _path.node;
                if(t.isFunctionDeclaration(path.node)){
                    if(!(t.isFunctionDeclaration(node)&&node.id.name==funcName))return;
                    console.log(node.id.name);
                }else{
                    console.log(referName);
                    debugger;
                };
                var body = node.body.body[0]
                if(!(t.isReturnStatement(body)))return;
                var params_ = [];
                node.params.map((ele,index)=>{
                    params_[index] = ele.name;
                });
                // 防止替换后的元素被重新替换 ===> 类似  a->b  b->c ====>除去arguments和params相交索引不等的情况
                // 相交且arguments_的所有索引小于params_使用倒序||相交且arguments_的所有索引大于params_使用顺序||重排序
                // -->排除参数和传参长度不等
                // 排除 多次嵌套  a->b[c(b)] b->c 除了arguments_中的组后一位,arguments_中的每一位元素        
                var index_ = params_.every((ele,index)=>{
                    var axa = arguments_.indexOf(ele)
                    return (axa<0)||(axa>=index);
                });
                var index__ = arguments_.every((ele)=>{
                    return params_.every((xle)=>{
                        return ele.indexOf(xle)<0;
                    })
                })
                if(index_){
                    arguments_.forEach((ele,index)=>{
                        _path.scope.rename(params_[index],ele,_path.scope.block);
                    })
                }else if(index__){
                    for(var i=arguments_.length-1;i>=0;i--){
                        _path.scope.rename(params_[i],arguments_[i],_path.scope.block);
                    };
                }else{
                    debugger;
                    return;
                }
                var call_node = _path.node.body.body[0].argument; //call_node 和 replaceWidth错误
                console.log(referpath.parentPath.toString())
                try{
                    referpath.parentPath.replaceWith(call_node);
                }catch(e){
                    debugger
                    return;
                };
                console.log(referpath.parentPath.toString());
                // generator(path.node.body.body[0].argument).code
            }
        });
    })    
}
